package component.menu.composite
{
	import component.menu.MenuClass;
	import component.menu.data.MenuData;
	import component.menu.data.MenuItemData;
	import component.menu.item.MenuItem;
	
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.utils.Dictionary;
	import flash.utils.Timer;
	
	import mx.utils.StringUtil;

	[Event(name="selectPath", type="component.menu.composite.CompositeMenuEvent")]
	public class CompositeMenuClass extends MenuClass
	{
		private static const ROLL_DELAY : Number = 200;
		
		public var menuRenderer : Class = CompositeMenu;
		public var parentMenu : CompositeMenuClass;
		public var parentMenuItem : MenuItem;
		
		public var selectOnClick : Boolean = true;
		
		protected var subMenues : Dictionary;
		protected var rollDelayTimer : Timer;
		protected var targetMenu : CompositeMenu;
		protected var targetItem : MenuItem;
		
		public function CompositeMenuClass()
		{
			super();
			
			subMenues = new Dictionary();
			
			rollDelayTimer = new Timer(ROLL_DELAY, 1);
			rollDelayTimer.addEventListener(TimerEvent.TIMER, handleRollDelayTimer);
			
			addEventListener(MouseEvent.ROLL_OUT, handleMenuRollOut);
		}
		
		public function selectPath(path : String) : void 
		{
			var segments : Array = path.split(".");
			var firstSegment : String = segments[0];
			
			var selectedItemData : MenuItemData;
			for each (var itemData : MenuItemData in _itemsData)
			{
				if (itemData.id == firstSegment)
				{
					selectedItemData = itemData;
					break;
				}
			}
			
			if (selectedItemData != null)
			{
				selectedItemData.selected = true;
				
				if (segments.length > 1)
				{
					var otherSegments : Array = segments.slice(1);
					path = otherSegments.join(".");
					
					var subMenu : CompositeMenuClass = CompositeMenuClass(subMenues[selectedItemData]);
					if (subMenu != null)
					{
						subMenu.selectPath(path);
					}
				}
			}
		}
		
		override protected function initializeMenuItems() : void
		{	
			for each (var itemData : MenuItemData in _itemsData)
			{
				var item : MenuItem = MenuItem(new itemRenderer());
				item.selectOnClick = false;
				item.data = itemData;
				
				addContentChild(item);
				
				item.addEventListener(MouseEvent.CLICK, handleItemClick);
				item.addEventListener(MouseEvent.ROLL_OVER, handleItemRollOver);
				item.addEventListener(MouseEvent.ROLL_OUT, handleItemRollOut);
				
				if (itemData is MenuData && MenuData(itemData).itemsData != null)
				{
					var menu : CompositeMenu = CompositeMenu(new menuRenderer());
					menu.itemsData = MenuData(itemData).itemsData;
					menu.parentMenu = this;
					menu.parentMenuItem = item;
					
					subMenues[itemData] = menu;
					
					menu.addEventListener(MouseEvent.ROLL_OUT, handleMenuRollOut);
				}
				
				layout.items = _contentChildren;
			}
		}
		
		protected function startRollDelayTimer() : void
		{
			if (rollDelayTimer.running)
			{
				resetRollDelayTimer();
			}
			rollDelayTimer.start();
		}
		
		protected function resetRollDelayTimer() : void 
		{
			if (rollDelayTimer.running)
			{
				rollDelayTimer.stop();
			}
			rollDelayTimer.reset();
		}
		
		override protected function selectItem(itemData : MenuItemData) : void 
		{
			deselectAllItems();
			
			itemData.selected = true;
			
			selectedData = itemData;
			
			if (parentMenu != null)
			{
				parentMenu.selectItem(parentMenu.targetItem.data);
			}
		}
		
		override protected function deselectItem(itemData : MenuItemData) : void 
		{
			itemData.selected = false;
			
			selectedData = null;
		}
		
		override protected function deselectAllItems() : void 
		{
			super.deselectAllItems();
			
			for each (var menu : CompositeMenuClass in subMenues)
			{
				if (targetMenu != menu)
				{
					menu.deselectAllItems();
				}
			}
		}
		
		override protected function dispatchSelectEvent(itemData : MenuItemData) : void 
		{
			var event : CompositeMenuEvent = new CompositeMenuEvent(CompositeMenuEvent.SELECT_PATH, true);
			event.selectionPath = getSelectionPath(targetItem.data.id);
			
			dispatchEvent(event);
		}
		
		protected function getSelectionPath(result : String) : String
		{
			if (parentMenu == null)
			{
				return result;
			}
			
			return StringUtil.substitute("{0}.{1}", parentMenu.getSelectionPath(parentMenu.targetItem.data.id), result);
		}
		
		protected function handleItemRollOver(e : MouseEvent) : void 
		{
			var menuItem : MenuItem = MenuItem(e.target);
			
			if (menuItem != targetItem && menuItem.enabled)
			{
				if (targetMenu != null)
				{
					targetMenu.hide();
					targetMenu = null;
				}
				
				targetItem = menuItem;
				targetMenu = subMenues[targetItem.data];
				
				startRollDelayTimer();
			}
		}
		
		protected function handleItemRollOut(e : MouseEvent) : void 
		{
			var menuItem : MenuItem = MenuItem(e.target);
			
			if (menuItem == targetItem && 
				targetMenu != null && !targetMenu.hitTestPoint(stage.mouseX, stage.mouseY, true))
			{
				targetItem = null;
				targetMenu.hide();	
				resetRollDelayTimer();
			}
		}
		
		protected function handleMenuRollOut(e : MouseEvent) : void 
		{
			if (targetItem != null && !targetItem.hitTestPoint(stage.mouseX, stage.mouseY, true))
			{
				if (targetMenu != null)
				{
					targetMenu.hide();
				}
				targetMenu = null;
				targetItem = null;
			}
		}
		
		protected function handleMenuHide(e : CompositeMenuEvent) : void 
		{	
			var menu : CompositeMenu = CompositeMenu(e.target);
			
			menu.removeEventListener(CompositeMenuEvent.HIDE, handleMenuHide);
			
			contentPane.removeChild(menu);
		}
		
		protected function handleRollDelayTimer(e : TimerEvent) : void 
		{
			resetRollDelayTimer();
			
			if (targetMenu != null)
			{
				targetMenu.x = targetItem.x + targetItem.width;
				targetMenu.y = targetItem.y;
				
				contentPane.addChild(targetMenu);
				
				targetMenu.addEventListener(CompositeMenuEvent.HIDE, handleMenuHide);
				
				targetMenu.show();
			}
		}
		
		override protected function handleItemClick(e : MouseEvent) : void 
		{
			if (targetItem.enabled)
			{
				if (selectOnClick)
				{
					if (targetItem.selected)
					{
						deselectItem(targetItem.data);
					}
					else
					{
						selectItem(targetItem.data);
						dispatchSelectEvent(null);
					}
				}
				else
				{
					dispatchSelectEvent(null);
				}
			}
		}
		
	}
}